/*
日志系统的基本接口和标准输出实现

提供日志管理，全局日志支持，系统日志打印，文件日志输出
*/
package log

import (
	"fmt"  // 提供格式化输入输出功能
	"io"   // 提供I/O接口（如Writer）
	"os"   // 提供操作系统功能（如标准输出、程序退出）
	"sync" // 提供同步原语（如互斥锁）
	"time" // 提供时间相关功能
)

/* //* 日志系统核心实现，定义日志级别、Logger接口和标准输出日志器，提供多级别日志记录功能，支持并发安全 */

// * 日志级别常量定义（使用iota自增，从0开始）
type Level int

const (
	//* 调试级别
	LevelDebug Level = iota
	//? 信息级别
	LevelInfo
	//todo 警告级别
	LevelWarn
	//& 错误级别
	LevelError
	//! 指明错误级别
	LevelFatal
)

// * String 返回日志级别的字符串表示（实现fmt.Stringer接口）
func (l Level) String() string {
	switch l {
	case LevelDebug:
		return "DEBUG"
	case LevelInfo:
		return "INFO"
	case LevelWarn:
		return "WARN"
	case LevelError:
		return "ERROR"
	case LevelFatal:
		return "FATAL"
	default:
		return "UNKNOWN"
	}
}

// * 日志记录接口
type Logger interface {
	// 记录调试级别日志
	Debug(args ...interface{})
	// Debugf 记录调试级别日志（格式化）
	Debugf(format string, args ...interface{})
	// Info 记录信息级别日志
	Info(args ...interface{})
	// Infof 记录信息级别日志（格式化）
	Infof(format string, args ...interface{})
	// Warn 记录警告级别日志
	Warn(args ...interface{})
	// Warnf 记录警告级别日志（格式化）
	Warnf(format string, args ...interface{})
	// Error 记录错误级别日志
	Error(args ...interface{})
	// Errorf 记录错误级别日志（格式化）
	Errorf(format string, args ...interface{})
	// Fatal 记录致命错误级别日志并退出程序
	Fatal(args ...interface{})
	// Fatalf 记录致命错误级别日志（格式化）并退出程序
	Fatalf(format string, args ...interface{})
	// SetLevel 设置日志级别
	SetLevel(level Level)
	// GetLevel 获取日志级别
	GetLevel() Level
	// SetOutput 设置日志输出
	SetOutput(w io.Writer)
}

// StdLogger 标准输出日志记录器，实现Logger接口
//
// 字段说明：
//
//   - level：当前日志级别（用于过滤日志）
//   - mu：互斥锁（保证并发写入安全）
//   - writer：日志输出目标（实现io.Writer接口，如os.Stdout、文件等）
type StdLogger struct {
	level  Level
	mu     sync.Mutex
	writer io.Writer
}

// 创建标准输出日志记录器
func NewStdLogger(level Level) *StdLogger {
	return &StdLogger{
		level:  level,
		writer: os.Stdout,
	}
}

// 设置日志级别
func (l *StdLogger) SetLevel(level Level) {
	l.mu.Lock()
	defer l.mu.Unlock()
	l.level = level
}

// 获取日志规则
func (l *StdLogger) GetLevel() Level {
	l.mu.Lock()
	defer l.mu.Unlock()
	return l.level
}

// 设置日志输出
func (l *StdLogger) SetOutput(w io.Writer) {
	l.mu.Lock()
	defer l.mu.Unlock()
	l.writer = w
}

// 记录调试级别日志
func (l *StdLogger) Debug(args ...interface{}) {
	l.log(LevelDebug, args...)
}

// Debugf 记录调试级别日志（格式化）
func (l *StdLogger) Debugf(format string, args ...interface{}) {
	l.logf(LevelDebug, format, args...)
}

// Info 记录信息级别日志
func (l *StdLogger) Info(args ...interface{}) {
	l.log(LevelInfo, args...)
}

// Infof 记录信息级别日志（格式化）
func (l *StdLogger) Infof(format string, args ...interface{}) {
	l.logf(LevelInfo, format, args...)
}

// Warn 记录警告级别日志
func (l *StdLogger) Warn(args ...interface{}) {
	l.log(LevelWarn, args...)
}

// Warnf 记录警告级别日志（格式化）
func (l *StdLogger) Warnf(format string, args ...interface{}) {
	l.logf(LevelWarn, format, args...)
}

// Error 记录错误级别日志
func (l *StdLogger) Error(args ...interface{}) {
	l.log(LevelError, args...)
}

// Errorf 记录错误级别日志（格式化）
func (l *StdLogger) Errorf(format string, args ...interface{}) {
	l.logf(LevelError, format, args...)
}

// Fatal 记录致命错误级别日志并退出程序
func (l *StdLogger) Fatal(args ...interface{}) {
	l.log(LevelFatal, args...)
	// 退出程序 exit 退出码1
	os.Exit(1)
}

// Fatalf 记录致命错误级别日志（格式化）并退出程序
func (l *StdLogger) Fatalf(format string, args ...interface{}) {
	l.logf(LevelFatal, format, args...)
	os.Exit(1)
}

// * 记录日志
func (l *StdLogger) log(level Level, args ...interface{}) {
	if level < l.GetLevel() {
		return
	}
	//* 使用变长参数记得展开，切片也可以用... 进行展开操作
	message := fmt.Sprint(args...)
	l.output(level, message)
}

// logf 记录格式化日志
func (l *StdLogger) logf(level Level, format string, args ...interface{}) {
	if level < l.GetLevel() {
		return
	}

	message := fmt.Sprintf(format, args...)
	l.output(level, message)
}

// ~ 输出日志
func (l *StdLogger) output(level Level, message string) {
	l.mu.Lock()
	defer l.mu.Unlock()
	timestamp := time.Now().Format("2006-01-02 15:04:05")
	logEntry := fmt.Sprintf("[%s] %s [%s] %s\n", LOG_PRIFIX, timestamp, level.String(), message)
	//* 注意这里，用Write输出的时候，也会带上格式化，总之算是把输出内容集中在一起了
	l.writer.Write([]byte(logEntry)) // 将日志条目转换为字节数组并写入输出目标

	/*
			该方法的核心功能是：将字节切片 p 中的数据写入到底层数据流（如文件、控制台、网络连接等），并返回两个值：
		n int：实际写入的字节数（正常情况下应等于 len(p)，但部分场景可能因错误导致写入不完整）。
		err error：写入过程中可能发生的错误（如磁盘满、网络断开等，成功时为 nil）。
		在日志系统中，Write 方法是连接日志内容与输出目标的 “桥梁”—— 无论输出目标是控制台、文件还是网络，只要它实现了 io.Writer 接口，就能通过该方法接收日志数据
	*/
}
